/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alexandre-barbosa.com/

 Copyright (c) 2008 Alexandre Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef STATEMENTS_H
#define STATEMENTS_H

#include "actions.h"
#include "cnome.h"
#include "directives.h"
#include "tokens.h"

namespace cnome {
template <typename ScannerT>
void
cpp::definition<ScannerT>::statements(cpp const& self)
    {
        using namespace actions;
        using namespace directive;
        using namespace util;

        statement =
               remain_scope_d[	labeled_statement ]
            |  remain_scope_d[	expression_statement ]  
            |  remain_scope_d[	compound_statement ] 
            |  remain_scope_d[	selection_statement ] 
            |  remain_scope_d[	iteration_statement ]
            |  remain_scope_d[	jump_statement ]
            |  remain_scope_d[	declaration_statement ]
            |  remain_scope_d[	try_block ]
        ;

        labeled_statement =
               ( IDENTIFIER >> COLON >> statement)                   
            |  ( CASE >> constant_expression >> COLON >> statement ) 
            |  ( DEFAULT >> COLON >> statement )
        ;

        expression_statement =
            !expression >> SEMICOLON
        ;

        selection_statement =
              (      IF >> LEFTPAREN >> condition >> RIGHTPAREN >> statement  
                 >>  if_p(lookahead_d[ELSE])[NOTHING].else_p[EPSILON]            ) 
            | (  IF  >> LEFTPAREN >> condition >> RIGHTPAREN >> statement 
                 >>  ELSE >> statement                                           ) 
            | ( SWITCH >> LEFTPAREN >> condition >> RIGHTPAREN >> statement      )
        ;

        condition =
               expression                                                              
            |  ( type_specifier_seq >> declarator >> ASSIGN >> assignment_expression )
        ;

        iteration_statement =
              ( WHILE >> LEFTPAREN >> condition >> RIGHTPAREN >> statement             ) 
			| ( DO >> statement >> WHILE >> LEFTPAREN >> expression >> RIGHTPAREN      )
			| (      FOR >> LEFTPAREN >> for_init_statement >> !condition >> SEMICOLON 
			     >>  !expression >> RIGHTPAREN >> statement                            )
        ;

        for_init_statement =
               expression_statement 
			|  simple_declaration
        ;

        jump_statement =
              ( BREAK >> SEMICOLON                 ) 
			| ( CONTINUE >> SEMICOLON              ) 
			| ( RETURN >> !expression >> SEMICOLON ) 
			| ( GOTO >> IDENTIFIER                 )
        ;

        declaration_statement =
            block_declaration
        ;

        compound_statement =
            LEFTBRACE >> !statement_seq >> RIGHTBRACE
        ;

        statement_seq =
            statement >> statement_seq_helper
        ;

        statement_seq_helper =
              ( statement >> statement_seq_helper ) 
			| EPSILON
        ;
        //  End grammar definition
         
        // turn on the debugging info.
        BOOST_SPIRIT_DEBUG_RULE(statement);
        BOOST_SPIRIT_DEBUG_RULE(labeled_statement);
        BOOST_SPIRIT_DEBUG_RULE(expression_statement);
        BOOST_SPIRIT_DEBUG_RULE(compound_statement);
        BOOST_SPIRIT_DEBUG_RULE(selection_statement);
        BOOST_SPIRIT_DEBUG_RULE(iteration_statement);
        BOOST_SPIRIT_DEBUG_RULE(jump_statement);
        BOOST_SPIRIT_DEBUG_RULE(declaration_statement);
        BOOST_SPIRIT_DEBUG_RULE(try_block);
        BOOST_SPIRIT_DEBUG_RULE(constant_expression);
        BOOST_SPIRIT_DEBUG_RULE(expression);
        BOOST_SPIRIT_DEBUG_RULE(condition);
        BOOST_SPIRIT_DEBUG_RULE(expression);
        BOOST_SPIRIT_DEBUG_RULE(type_specifier_seq);
        BOOST_SPIRIT_DEBUG_RULE(declarator);
        BOOST_SPIRIT_DEBUG_RULE(assignment_expression);
        BOOST_SPIRIT_DEBUG_RULE(for_init_statement);
        BOOST_SPIRIT_DEBUG_RULE(expression_statement);
        BOOST_SPIRIT_DEBUG_RULE(simple_declaration);
        BOOST_SPIRIT_DEBUG_RULE(block_declaration);
        BOOST_SPIRIT_DEBUG_RULE(compound_statement);
        BOOST_SPIRIT_DEBUG_RULE(statement_seq);
        BOOST_SPIRIT_DEBUG_RULE(statement_seq_helper);

        BOOST_SPIRIT_DEBUG_RULE(IDENTIFIER);
        BOOST_SPIRIT_DEBUG_RULE(COLON);
        BOOST_SPIRIT_DEBUG_RULE(CASE);
        BOOST_SPIRIT_DEBUG_RULE(DEFAULT);
        BOOST_SPIRIT_DEBUG_RULE(SEMICOLON);
        BOOST_SPIRIT_DEBUG_RULE(IF);
        BOOST_SPIRIT_DEBUG_RULE(LEFTPAREN);
        BOOST_SPIRIT_DEBUG_RULE(RIGHTPAREN);
        BOOST_SPIRIT_DEBUG_RULE(ELSE);
        BOOST_SPIRIT_DEBUG_RULE(SWITCH);
        BOOST_SPIRIT_DEBUG_RULE(ASSIGN);
        BOOST_SPIRIT_DEBUG_RULE(WHILE);
        BOOST_SPIRIT_DEBUG_RULE(DO);
        BOOST_SPIRIT_DEBUG_RULE(FOR);
        BOOST_SPIRIT_DEBUG_RULE(SEMICOLON);
        BOOST_SPIRIT_DEBUG_RULE(BREAK);
        BOOST_SPIRIT_DEBUG_RULE(CONTINUE);
        BOOST_SPIRIT_DEBUG_RULE(RETURN);
        BOOST_SPIRIT_DEBUG_RULE(GOTO);
        BOOST_SPIRIT_DEBUG_RULE(IDENTIFIER);
        BOOST_SPIRIT_DEBUG_RULE(LEFTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(RIGHTBRACE);
        BOOST_SPIRIT_DEBUG_RULE(EPSILON);
    }
}  // namespace cnome
#endif // STATEMENTS_H
